package io.kiki.stack.netty.channelManager;

import io.kiki.stack.netty.config.ClientOption;
import io.kiki.stack.netty.config.Config;
import io.kiki.stack.netty.config.Configs;
import io.kiki.stack.netty.util.StringUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Slf4j
@Setter
@Getter
public class RandomChannelSelectStrategy implements ChannelSelectStrategy {


    private static final int MAX_TIMES = 5;
    private final Random random = new Random();
    private final Config config;

    public RandomChannelSelectStrategy(Config config) {
        this.config = config;
    }

    @Override
    public Channel select(List<Channel> channelList) {
        try {
            if (channelList == null) {
                return null;
            }
            int size = channelList.size();
            if (size == 0) {
                return null;
            }

            Channel result;
            if (config != null && config.option(ClientOption.Channel_monitor_switch)) {
                List<Channel> list = new ArrayList<Channel>();
                for (Channel channel : channelList) {
                    String serviceStatus = (String) channel.getAttribute(Configs.CONN_SERVICE_STATUS);
                    if (!StringUtils.equals(serviceStatus, Configs.CONN_SERVICE_STATUS_OFF)) {
                        list.add(channel);
                    }
                }
                if (list.size() == 0) {
                    throw new Exception("No available channel when select in RandomSelectStrategy.");
                }
                result = randomGet(list);
            } else {
                result = randomGet(channelList);
            }
            return result;
        } catch (Throwable e) {
            log.error("Choose channel failed using RandomSelectStrategy!", e);
            return null;
        }
    }

    private Channel randomGet(List<Channel> channelList) {
        if (null == channelList || channelList.isEmpty()) {
            return null;
        }

        int size = channelList.size();
        int tries = 0;
        Channel channel = null;
        while ((channel == null || !channel.isFine()) && tries++ < MAX_TIMES) {
            channel = channelList.get(this.random.nextInt(size));
        }

        if (channel != null && !channel.isFine()) {
            channel = null;
        }
        return channel;
    }
}
